package com.trailwalker.traceability.service;

import com.trailwalker.JavaUtils.log.LogUtils;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiConsumer;

/**
 * @author Trailwalker
 * @create 2021-11-18 17:45
 */
public class DirectoryListenService {

    public static final String TAG = DirectoryListenService.class.getSimpleName();

    private ExecutorService fixedThreadPool;
    private WatchService mWatchService;
    private String mListenedPath;
    private BiConsumer<String, WatchEvent.Kind<?>> mCallback;

    public DirectoryListenService(String listenedPath, BiConsumer<String, WatchEvent.Kind<?>> callback) {
        try {
            mWatchService = FileSystems.getDefault().newWatchService();
            fixedThreadPool = Executors.newCachedThreadPool();
            mListenedPath = listenedPath;
            mCallback = callback;
        } catch (IOException e) {
            e.printStackTrace();
            LogUtils.logE(e);
        }
    }

    public void start() {
        if (fixedThreadPool != null) {
            Path path = Paths.get(mListenedPath);
            //注册监听事件，文件的修改、删除和创建
            try {
                path.register(mWatchService,
                        //StandardWatchEventKinds.ENTRY_MODIFY,
                        //StandardWatchEventKinds.ENTRY_DELETE,
                        StandardWatchEventKinds.ENTRY_CREATE);
                fixedThreadPool.execute(new Listner(mWatchService, mListenedPath, mCallback));
            } catch (IOException e) {
                e.printStackTrace();
                LogUtils.logE(e);
            }
        }
    }

    public void finish() {
        if (!fixedThreadPool.isShutdown()) {
            fixedThreadPool.shutdownNow();
        }
    }
}

class Listner implements Runnable {
    private final WatchService mWatchService;
    private final String mDirectoryPath;
    private BiConsumer<String, WatchEvent.Kind<?>> mCallback;

    public Listner(WatchService watchService, String directoryPath, BiConsumer<String, WatchEvent.Kind<?>> callback) {
        mWatchService = watchService;
        mDirectoryPath = directoryPath;
        mCallback = callback;
    }

    public void run() {
        try {
            LogUtils.log(DirectoryListenService.TAG, "start listen");
            while (true) {
                WatchKey watchKey = mWatchService.take();
                List<WatchEvent<?>> watchEventList = watchKey.pollEvents();
                for (WatchEvent<?> watchEvent : watchEventList) {
                    if (mCallback != null) {
                        mCallback.accept(mDirectoryPath + File.separator + watchEvent.context(), watchEvent.kind());
                    }
                }
                if (!watchKey.reset()) {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.logE(e);
        } finally {
            LogUtils.log(DirectoryListenService.TAG, "listen finished");
            try {
                mWatchService.close();
            } catch (IOException e) {
                e.printStackTrace();
                LogUtils.logE(e);
            }
        }

    }
}
